#include"workCmd.h"
#define FILESIZE_THRESHOLD (100*1024*1024)
int recvn(int sockfd, void *buf, int length){
    int total = 0;
    char *p = (char *)buf;
    while(total < length){
        ssize_t sret = recv(sockfd,p+total,length-total,0);
        if(sret<=0)return -1;
        total += sret;
    }
    return total;
}

//recvn封装版本，强制recv完，进度条
//大文件秒传，小文件慢慢传
int recvFile(int netfd){
    train_t train;
    char filename[4096] = {0};
    recvn(netfd,&train.length,sizeof(train.length));//收火车头
    recvn(netfd,train.data,train.length);//收车厢
    memcpy(filename,train.data,train.length);
    filename[train.length] = '\0';
    printf("Receiving file: %s\n",filename);

    int fd = open(filename,O_RDWR|O_CREAT|O_TRUNC,0666);
    ERROR_CHECK(fd,-1,"open");

    off_t filesize = 0;
    recvn(netfd,&train.length,sizeof(train.length));
    recvn(netfd,train.data,train.length);
    memcpy(&filesize,train.data,train.length);

    printf("Filesize = %ld\n",filesize);
    if(filesize < FILESIZE_THRESHOLD){
        printf("Tiny file (< %.2lf MB) Send by Train\n", 1.0*FILESIZE_THRESHOLD / (1024 * 1024));
        off_t currsize = 0;
        while(1){
            recvn(netfd,&train.length,sizeof(train.length));
            if(train.length == 0)break;
            recvn(netfd,train.data,train.length);
            write(fd,train.data,train.length);
            currsize+=train.length;
            printf("%5.2lf%%\r",100.0*currsize/filesize);
            fflush(stdout);
        }
    }
    else{
        printf("Huge file (> %.2lf MB) Send by zero-copy\n", 1.0*FILESIZE_THRESHOLD / (1024 * 1024));
        off_t currsize = 0;
        char buf[8192]={0};
        while(currsize<filesize){
            ssize_t len = recv(netfd,buf,sizeof(buf),0);
            if(len<=0)break;
            write(fd,buf,len);
            currsize+=len;
            printf("%5.2lf%%\r",100.0*currsize/filesize);
            fflush(stdout);
        }
        recvn(netfd,&train.length,sizeof(train.length));
    }
    printf("100.00%%\n");
    close(fd);
    return 0;
}

int sendFile(int netFd,char *file){
    train_t train;
    train.length = strlen(file);
    memcpy(train.data,file,train.length);
    printf("%d ,%s\n",train.length,train.data);
    send(netFd,&train.length,sizeof(train.length),MSG_NOSIGNAL);
    send(netFd,train.data,train.length,MSG_NOSIGNAL);

    int fd = open(file,O_RDWR);
    ERROR_CHECK(fd,-1,"open");

    struct stat statbuf;
    ERROR_CHECK((fstat(fd,&statbuf)),-1,"fstat");
    off_t filesize = statbuf.st_size;
    
    train.length = sizeof(filesize);
    memcpy(train.data,&filesize,train.length);
    send(netFd,&train.length,sizeof(train.length),MSG_NOSIGNAL);
    send(netFd,train.data,train.length,MSG_NOSIGNAL);

    printf("Filesize = %ld\n",filesize);
    //小文件秒传，大文件小火车传
    if(filesize < FILESIZE_THRESHOLD){
        printf("Tiny file (< %.2lf MB) Send by Train\n", 1.0*FILESIZE_THRESHOLD / (1024 * 1024));
        while(1){
            bzero(train.data,sizeof(train.data));
            ssize_t ret = read(fd,train.data,sizeof(train.data));
            train.length = ret;
            send(netFd,&train.length,sizeof(train.length),MSG_NOSIGNAL);
            if(ret == 0)break;
            send(netFd,train.data,train.length,MSG_NOSIGNAL);
        }
    }
    else{
        printf("Huge file (> %.2lf MB) Send by zero-copy\n", 1.0*FILESIZE_THRESHOLD / (1024 * 1024));
        off_t offset = 0;
        while(offset<filesize){
            //sendfile() 会自动更新 offset 的值
            ssize_t sret = sendfile(netFd,fd,&offset,filesize-offset);
            ERROR_CHECK(sret,-1,"sendfile");
        }
        train.length = 0;
        send(netFd,&train.length,sizeof(train.length),MSG_NOSIGNAL);
    }
    close(fd);
    return 0;
}
